﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Globalization;
using HtmlAgilityPack;
using System.Text.RegularExpressions;

namespace OlapProject
{
    class PropertyAndMoreParser : IParser
    {
        private int currentPageNumber = 1;
        private int lastPageNumber;

        private const String baseURL = "http://www.propertyandmoreproperty.com";
        private const String pageName = "pamp";

        private List<PropertyVO> properties;
        private Dictionary<String, String> types;

        private HtmlWeb htmlWeb;
        private String currentPage;
        private HtmlDocument document;
        private HtmlNode listNode;

        public PropertyAndMoreParser()
        {
            properties = new List<PropertyVO>();
            htmlWeb = new HtmlWeb();
            prepareTypes();
        }

        private void init()
        {            
            properties.Clear();
            currentPage = "http://www.propertyandmoreproperty.com/list_view.php?search_continent=EU&search_country=&search_region=&search_type=&search_size=&search_more=&search_above=&search_under=&Submit.x=96&Submit.y=9&Submit=Submit"; // Start page.
            document = htmlWeb.Load(currentPage);
        }

        public List<PropertyVO> getData()
        {
            Log.writeLine("Propery and more property STARTING ...");
            init();
            getNumberOfAllPages();
            parseAllPages();

            return properties;
        }

        public void prepareTypes()
        {
            types = new Dictionary<string, string>()
            {
                // Key => Value
                {"apartment", "apartment"},
                {"house", "house"},
                {"site", "land"},
                {"apartmentblock", "apartment"},
                {"farm", "farm"},
                {"industrial", "industrial"},
                {"commercial", "commercial"},
                {"office", "office"},
                {"other", "other"},
                {"garageparking", "garage-parking"},
            };
        }

        public void getNumberOfAllPages()
        {
            HtmlNodeCollection paginationLinks = document.DocumentNode.SelectNodes("//a[contains(@class, 'pager_link')]");
            HtmlNode lastLink = paginationLinks.Last();
            String lastValue = baseURL + lastLink.Attributes["href"].Value.ToString();
            HtmlDocument documentLastPage = htmlWeb.Load(lastValue);
            HtmlNodeCollection lastPaginationLinks = documentLastPage.DocumentNode.SelectNodes("//a[contains(@class, 'pager_link')]");
            int.TryParse(lastPaginationLinks.Last().InnerText.ToString(), out lastPageNumber);

            checkDebugMode();
        }

        private void checkDebugMode()
        {
            if (DebugModel.debugMode && (lastPageNumber > DebugModel.MAX_PAGE_IN_DEBUG))
            {
                lastPageNumber = DebugModel.MAX_PAGE_IN_DEBUG;
            }
        }

        public void parseAllPages()
        {
            do{
                Log.parserLog(currentPageNumber, "Property And More Property");

                // Load next page.
                if (currentPageNumber > 1)
                {
                    HtmlNodeCollection paginationLinks = document.DocumentNode.SelectNodes("//a[contains(@class, 'pager_link')]");

                    foreach (HtmlNode link in paginationLinks)
                        if (link.InnerText.ToString() == currentPageNumber.ToString())
                        {
                            currentPage = baseURL + link.Attributes["href"].Value.ToString();
                            continue;
                        }

                    document = htmlWeb.Load(currentPage);
                }

                // Node for page with links.
                listNode = document.DocumentNode;
                
                if (listNode != null)
                {
                    HtmlNodeCollection allLinksPerPage = listNode.SelectNodes("//td[starts-with(@class, 'img_border')]/a");

                    if (allLinksPerPage == null) Console.WriteLine("NULL");
                    else
                    {
                        foreach (HtmlNode link in allLinksPerPage)
                        {
                            HtmlDocument detailsDocument = htmlWeb.Load(baseURL+ "/" + link.Attributes["href"].Value.ToString());

                            PropertyVO property = new PropertyVO();
                            property.source = pageName;
                            property.datetime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

                            // Address.
                            listNode = detailsDocument.DocumentNode.SelectSingleNode("//td[@class='orange_20']//strong");
                            if (listNode != null)
                                addAddress(property, listNode.InnerText);

                            // Price.
                            listNode = detailsDocument.DocumentNode.SelectSingleNode("//span[@class='black_20']//strong");
                            if (listNode != null)
                                addPrice(property, listNode.InnerText);

                            // Type.
                            listNode = detailsDocument.DocumentNode.SelectSingleNode("//table[@class='black_11']//tr[2]//td[1]//strong");
                            if (listNode != null && listNode.InnerText.ToString() == "Property Type:")
                            {
                                listNode = detailsDocument.DocumentNode.SelectSingleNode("//table[@class='black_11']//tr[2]//td[2]");
                                addType(property, listNode.InnerText);
                            }

                            // Live square.
                            listNode = detailsDocument.DocumentNode.SelectSingleNode("//table[@class='black_11']//tr[9]//td[1]//strong");
                            //listNode = detailsDocument.DocumentNode.SelectSingleNode("//table[@class='black_11']//strong[text()='Floor area:']");
                            if (listNode != null && listNode.InnerText.ToString() == "Floor area:")
                            {
                                listNode = detailsDocument.DocumentNode.SelectSingleNode("//table[@class='black_11']//tr[9]//td[2]");
                                addLiveArea(property, listNode.InnerText);
                            }

                            // Land square.
                            listNode = detailsDocument.DocumentNode.SelectSingleNode("//table[@class='black_11']//tr[8]//td[1]//strong");
                            if (listNode != null && listNode.InnerText.ToString() == "size of land:")
                            {
                                listNode = detailsDocument.DocumentNode.SelectSingleNode("//table[@class='black_11']//tr[8]//td[2]");
                                addLandArea(property, listNode.InnerText);
                            }

                            // Bedrooms.
                            listNode = detailsDocument.DocumentNode.SelectSingleNode("//table[@class='black_11']//tr[10]//td[1]//strong");
                            if (listNode != null && listNode.InnerText.ToString() == "No. Of Bedrooms:")
                            {
                                listNode = detailsDocument.DocumentNode.SelectSingleNode("//table[@class='black_11']//tr[10]//td[2]");
                                addBedrooms(property, listNode.InnerText);
                            }

                            // Add property to list.
                            properties.Add(property);
                        }
                    }
                }

                currentPageNumber++;

            }while(currentPageNumber <= lastPageNumber);

        } // End parse.

        public void addAddress(PropertyVO property, String parsedAddress)
        {
            if (String.IsNullOrEmpty(parsedAddress))
                return;

            parsedAddress = parsedAddress.Trim();
            String[] partsOfAddress = parsedAddress.Split(',');
            int counter = partsOfAddress.Count();
            if (counter >= 1)
                property.country = partsOfAddress[0].Trim().ToLower();
            if (counter >= 2)
                property.city = partsOfAddress[1].Trim().ToLower();
            if (counter >= 3)
                property.district = partsOfAddress[2].Trim().ToLower();
        }

        public void addPrice(PropertyVO property, String price)
        {
            if (String.IsNullOrEmpty(price))
                return;
            else
            {
                String convertedPrice = price.Split(';')[1].Replace(",", "").Trim().ToLower();
                if (!String.IsNullOrEmpty(convertedPrice))
                    property.price = Decimal.Parse(convertedPrice, CultureInfo.InvariantCulture);
            }
        }

        public void addType(PropertyVO property, String type)
        {
            if (String.IsNullOrEmpty(type))
            {
                property.type = "unspecified";
                return;
            }

            type = type.Trim().Replace(" ", "").Replace("\\", "").ToLower();

            if (types.ContainsKey(type))
                property.type = types[type];
            else
                property.type = "other";
        }

        public void addLiveArea(PropertyVO property, String area)
        {
            if (String.IsNullOrEmpty(area) || area.Contains("-"))
                return;
            else
            {
                String convertedArea = area.Split(' ')[0].Trim().ToLower();
                // Jezeli bedzie tylko podane "m", zamien na pusty znak i sprawdz stringa.
                convertedArea = Regex.Replace(convertedArea, "[a-zA-Z]", "");
                if(!String.IsNullOrEmpty(convertedArea))
                    property.area = Decimal.Parse(convertedArea, CultureInfo.InvariantCulture);
            }
        }

        public void addLandArea(PropertyVO property, String area)
        {
            if (String.IsNullOrEmpty(area) || area.Contains("-"))
                return;
            else
            {
                String convertedArea = area.Split(' ')[0].Trim().ToLower();
                // Jezeli bedzie tylko podane "m", zamien na pusty znak i sprawdz stringa.
                convertedArea = Regex.Replace(convertedArea, "[a-zA-Z]", "");
                if (!String.IsNullOrEmpty(convertedArea))
                    property.plotArea = Decimal.Parse(convertedArea, CultureInfo.InvariantCulture);
            }
        }

        public void addBedrooms(PropertyVO property, String bedrooms)
        {
            if (String.IsNullOrEmpty(bedrooms) || bedrooms.Contains("-"))
                return;
            else
            {
                String convertedBedrooms = bedrooms.Split(' ')[0].Split('+')[0].Trim().ToLower();
                // Jezeli bedzie tylko tekst, zamien na puste znaki i sprawdz stringa.
                convertedBedrooms = Regex.Replace(convertedBedrooms, "[a-zA-Z]", "");
                if (!String.IsNullOrEmpty(convertedBedrooms))
                    property.bedrooms = Int16.Parse(convertedBedrooms);
            }
        }
            
    } // End class.
}
